
package jp.moisture.othello.player;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import jp.moisture.othello.board.Board;
import jp.moisture.othello.board.Board.State;
import jp.moisture.othello.board.Cell;
import jp.moisture.othello.board.Stone;
import jp.moisture.othello.player.search.CandidateCell;

import org.apache.commons.lang3.StringUtils;

public class AlphaBetaPlayer extends Player {

    static class Answer {
        Cell mCell;
    }

    private static final int MAX = 100000000;
    private static final int MIN = -MAX;
//    private static final int DEPTH = 8;
    private static final int DEPTH = 6;
//    private static final int DEPTH = 4;

    public AlphaBetaPlayer(String name) {
        super(name);
    }

    int mMaxDepth;

    public Cell next() {
        List<Cell> cells = mBoard.findPutableCells(mColor);
        if (cells.isEmpty()) {
            return null;
        }
        // Cell cell = cells.get(0);
        // System.out.println(mBoard);
        // mBoard.setStone(cell.getX(), cell.getY(), mColor);
        // System.out.println(mBoard);
        // mBoard.pop();
        // System.out.println(mBoard);
        // System.exit(0);
        // return cells.get(0);
        Answer answer = new Answer();
        int value;
        Board board = new Board(mBoard);
        mMaxDepth = DEPTH;
        if (board.getEmptyCellCount() <= 20) {
            mMaxDepth = board.getEmptyCellCount();
        }
        value = search(board, mMaxDepth, MIN, MAX, mColor, mColor == Stone.BLACK ? Stone.WHITE : Stone.BLACK, false, answer);
        System.out.println("value : " + value);
        if (value == MAX) {
            mMind = MIND_WINNER;
        } else if (value == MIN) {
            mMind = MIND_LOOSER;
        }

        if (answer.mCell == null) {
            return null;
        } else {
            return mBoard.getCell(answer.mCell.getX(), answer.mCell.getY());
        }
    }

    private final int search(Board board, int depth, int alpha, int beta, int myColor, int otherColor, boolean pass, Answer targetAnswer) {

        int max = alpha;

        if (depth == 0) {
            List<CandidateCell> candidateCells = findPutableCells(board, myColor, otherColor);
            if (candidateCells.isEmpty()) {
                return -State.WON;
            }
            CandidateCell candidateCell = candidateCells.get(0);
            return candidateCell.mState.getPoint(myColor);
        }

        List<Cell> cells = board.findPutableCells(myColor);
        List<CandidateCell> candidateCells = new ArrayList<>();
        for (Cell cell : cells) {
            CandidateCell candidateCell = new CandidateCell(myColor, board, cell);
            if (!candidateCell.isWideMarginWon(otherColor)) {
                candidateCells.add(candidateCell);
            }
        }
        Collections.sort(candidateCells);
        // System.out.println(candidateCells);
        // if (candidateCells.size() > 1) {
        // candidateCells = candidateCells.subList(0, 1);
        // }

        for (CandidateCell cell : candidateCells) {
            int value = -search(cell.mBoard, depth - 1, -beta, -max, otherColor, myColor, false, null);
//            if (depth == mMaxDepth) {
//                int repeat = mMaxDepth - depth;
//                if (repeat < 0) {
//                    repeat = 0;
//                }
//                System.out.println(StringUtils.repeat(' ', repeat) + "depth : " + depth + " : " + Stone.toString(myColor) + cell.mCell.toStringData() + " : "
//                        + value + " a:" + alpha + " b:" + beta);
//            }

            if (value > max) {
                max = value;
                if (targetAnswer != null) {
                    targetAnswer.mCell = cell.mCell;
                }
                if (max >= beta) {
                    return beta;
                }
            }
        }
        if (cells.isEmpty()) {
            if (pass) {
                if (targetAnswer != null) {
                    if (!candidateCells.isEmpty()) {
                        targetAnswer.mCell = candidateCells.get(0).mCell;
                    } else if (!cells.isEmpty()) {
                        targetAnswer.mCell = cells.get(0);
                    }
                }
                max = board.getState().getPoint(myColor);
            } else {
                if (targetAnswer != null) {
                    targetAnswer.mCell = null;
                }
                // Board newBoard = new Board(board);
                max = -search(board, depth, -beta, -max, otherColor, myColor, true, null);
            }

        }
        return max;

    }

    private final List<CandidateCell> findPutableCells(Board board, int myColor, int otherColor) {
        List<Cell> cells = board.findPutableCells(myColor);
        List<CandidateCell> candidateCells = new ArrayList<>();
        for (Cell cell : cells) {
            CandidateCell candidateCell = new CandidateCell(myColor, board, cell);
            if (!candidateCell.isWideMarginWon(otherColor)) {
                candidateCells.add(candidateCell);
            }
        }
        Collections.sort(candidateCells);
        return candidateCells;
    }

}
